package com.ccteam.fluidmusic.fluidmusic.common.utils.notification

import android.app.PendingIntent
import android.content.ContentResolver
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.provider.MediaStore
import android.support.v4.media.session.MediaSessionCompat
import com.ccteam.fluidmusic.fluidmusic.R
import com.ccteam.fluidmusic.fluidmusic.common.utils.AlbumArtCache
import com.ccteam.fluidmusic.fluidmusic.common.utils.FluidMusicControlDispatcher
import com.google.android.exoplayer2.Player
import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.util.NotificationUtil
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch

/**
 *
 * @author Xiaoc
 * @since 2021/1/2
 *
 * 通知栏处理器
 * 该通知栏处理器负责显隐通知栏，并且显示对应通知栏内容
 */
class NotificationHandler (
    private val albumArtCache: AlbumArtCache,
    context: Context,
    private val session: MediaSessionCompat,
    notificationListener: PlayerNotificationManager.NotificationListener
) {

    // 协程组件
    private val serviceJob = SupervisorJob()
    private val serviceScope = CoroutineScope(Dispatchers.Main + serviceJob)

    /**
     * 媒体通知栏管理器
     */
    private val notificationManager: PlayerNotificationManager

    init {
        NotificationUtil.createNotificationChannel(context,
            NOW_PLAYING_CHANNEL_ID,
            R.string.notification_channel,
            R.string.notification_channel_description,NotificationUtil.IMPORTANCE_LOW)
        notificationManager = PlayerNotificationManager(
            context, NOW_PLAYING_CHANNEL_ID, NOW_PLAYING_NOTIFICATION_ID,
            DescriptionAdapter(),
            notificationListener,
            null
        ).apply {
            setMediaSessionToken(session.sessionToken)
            setSmallIcon(R.drawable.ic_logo_small)
            // 禁用快进、快退图标
            setControlDispatcher(FluidMusicControlDispatcher(0,0))
        }
    }

    /**
     * 隐藏通知栏
     * 根据API提示，将player设置为null即可隐藏通知栏
     */
    fun hideNotification(){
        notificationManager.setPlayer(null)
    }

    /**
     * 显示通知栏
     */
    fun showNotification(player: Player){
        notificationManager.setPlayer(player)
    }

    /**
     * 结束通知栏内容
     * 关闭协程，避免内存泄漏
     */
    fun close(){
        hideNotification()
        serviceJob.cancel()
    }

    /**
     * 描述适配器
     * 设置通知栏中要显示内容的描述信息
     */
    private inner class DescriptionAdapter:PlayerNotificationManager.MediaDescriptionAdapter{

        var currentIconUri: Uri? = null
        var currentBitmap: Bitmap? = null

        /**
         * 设置通知栏标题文字
         * 此处设置为媒体的标题
         */
        override fun getCurrentContentTitle(player: Player) =
            session.controller.metadata.description.title.toString()

        /**
         * 返回通知栏需要的Intent，用于点击通知栏跳转
         */
        override fun createCurrentContentIntent(player: Player): PendingIntent? =
            session.controller.sessionActivity

        /**
         * 设置通知栏内容文字
         * 此处设置为媒体的歌手信息
         */
        override fun getCurrentContentText(player: Player) =
            session.controller.metadata.description.subtitle.toString()

        /**
         * 设置通知栏副标题文字
         * 此处设置为 当前播放列表所在位置/播放列表总数
         */
        override fun getCurrentSubText(player: Player): CharSequence {
            val currentIndex = player.currentWindowIndex + 1
            val allCount = player.mediaItemCount
            return "$currentIndex/$allCount"
        }

        /**
         * 设置媒体通知栏的大图，需要一个Bitmap
         * 该方法会使用 [AlbumArtCache] 检索对应 artMediaUri 的Bitmap，将其返回至该处
         */
        override fun getCurrentLargeIcon(
            player: Player,
            callback: PlayerNotificationManager.BitmapCallback
        ): Bitmap? {
            // 获得封面地址Uri
            // 专辑封面的存储Uri
            val cacheKeyUri = session.controller.metadata.description.iconUri
            // 真正需要去解析的封面地址（由于AndroidQ以上专辑封面解析Uri和实际Uri不同）
            var realParseUri = session.controller.metadata.description.iconUri

            if(ContentResolver.SCHEME_CONTENT == realParseUri?.scheme
                && MediaStore.AUTHORITY == realParseUri.authority
                && realParseUri.pathSegments.contains("audio") &&
                android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q){
                // 如果是AndroidQ的本地资源，封面Uri为Music的Uri
                realParseUri = session.controller.metadata.description.mediaUri
            }
            // 这里做了防止重复加载Bitmap的措施，做了缓存
            // 当还是相同专辑封面Uri是不进行封面的加载，直接使用不进行加载
            // 并且使用协程异步加载
            return if(currentIconUri != cacheKeyUri || currentBitmap == null){
                currentIconUri = cacheKeyUri
                handleAlbumArt(cacheKeyUri,realParseUri,callback)
                null
            } else {
                currentBitmap
            }
        }

        /**
         * 处理封面内容
         */
        private fun handleAlbumArt(cacheKeyUri: Uri?,
                                   realParseUri: Uri?,
                                   callback: PlayerNotificationManager.BitmapCallback){
            serviceScope.launch {
                if(cacheKeyUri != null && realParseUri != null){
                    albumArtCache.resolveBitmapByUri(
                        cacheKeyUri,
                        realParseUri,
                        false,{},{ bitmap ->
                            currentBitmap = bitmap
                            callback.onBitmap(bitmap)
                        })
                } else {
                    val bitmap = albumArtCache.resolveResourceToBitmap(R.drawable.exo_ic_default_album_image)
                    callback.onBitmap(bitmap)
                }
            }
        }
    }

}

const val NOW_PLAYING_CHANNEL_ID = "com.ccteam.fluidmusic.NOW_PLAYING"
const val NOW_PLAYING_NOTIFICATION_ID = 0xb201
